package org.dromara.system.controller.monitor;

import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysLogininforBo;
import org.dromara.system.domain.vo.SysLogininforVo;
import org.dromara.system.service.ISysLogininforService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/**
 * @Author 刘武贵
 * @Date 2024/8/15 22:00
 * @Description 功能描述：系统访问记录
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/monitor/logininfor")
public class SysLogininforController extends BaseController {

    /**
     * 系统访问日志情况信息 服务层
     */
    private final ISysLogininforService logininforService;

    /**
     * 获取系统访问记录列表
     *
     * @param logininfor 登录日志查询条件 {@link SysLogininforBo}
     * @param pageQuery 分页查询条件 {@link PageQuery}
     * @return 返回分页的登录日志数据 {@link TableDataInfo} 包含登录日志数据列表 {@link SysLogininforVo}
     */
    @SaCheckPermission("monitor:logininfor:list")
    @GetMapping("/list")
    public TableDataInfo<SysLogininforVo> list(SysLogininforBo logininfor, PageQuery pageQuery) {
        return logininforService.selectPageLogininforList(logininfor, pageQuery);
    }

    /**
     * 导出系统访问记录列表
     *
     * @param logininfor 登录日志查询条件封装类
     * @param response HTTP响应对象，用于输出Excel文件
     */
    @Log(title = "登录日志", businessType = BusinessType.EXPORT)
    @SaCheckPermission("monitor:logininfor:export")
    @PostMapping("/export")
    public void export(SysLogininforBo logininfor, HttpServletResponse response) {
        // 根据登录日志查询条件，获取登录日志数据列表
        List<SysLogininforVo> list = logininforService.selectLogininforList(logininfor);
        // 使用ExcelUtil工具类将登录日志数据列表导出到Excel文件中
        ExcelUtil.exportExcel(list, "登录日志", SysLogininforVo.class, response);
    }

    /**
     * 批量删除登录日志
     * 该方法通过调用logininforService的deleteLogininforByIds方法，实现根据ID批量删除访问记录的功能
     * 注释中解释了参数infoIds的来源和含义，以及返回值的类型和意义
     *
     * @param infoIds 日志ids
     * @return 使用通用的Ajax响应封装类R返回操作结果，操作成功时不返回具体数据，故参数为Void
     */
    @SaCheckPermission("monitor:logininfor:remove")
    @Log(title = "登录日志", businessType = BusinessType.DELETE)
    @DeleteMapping("/{infoIds}")
    public R<Void> remove(@PathVariable Long[] infoIds) {
        return toAjax(logininforService.deleteLogininforByIds(infoIds));
    }

    /**
     * 清理系统访问记录
     * 本方法调用logininforService的cleanLogininfor方法来清理过期的登录日志数据
     * 主要用于保持数据库的登录日志表处于最新状态，移除超出保存期限的记录
     *
     * @return 返回操作结果，成功时返回R.ok()
     */
    @SaCheckPermission("monitor:logininfor:remove")
    @Log(title = "登录日志", businessType = BusinessType.CLEAN)
    @DeleteMapping("/clean")
    public R<Void> clean() {
        logininforService.cleanLogininfor();
        return R.ok();
    }

    /**
     * 解锁用户账户
     * 该方法用于解锁因密码输入错误次数过多而被临时锁定的用户账户
     * 当用户账户由于多次密码输入错误达到一定次数后，系统会临时锁定账户
     * 此方法通过删除与用户相关的锁定记录，实现账户的解锁
     *
     * @param userName 用户名，用于标识锁定的账户
     * @return 返回响应结果，R<Void>表示无具体返回内容
     */
    @SaCheckPermission("monitor:logininfor:unlock")
    @Log(title = "账户解锁", businessType = BusinessType.OTHER)
    @GetMapping("/unlock/{userName}")
    public R<Void> unlock(@PathVariable("userName") String userName) {
        // 构造Redis中的键名，格式为：PWD_ERR_CNT_KEY + 用户名
        String loginName = GlobalConstants.PWD_ERR_CNT_KEY + userName;
        // 检查Redis中是否存在该用户的相关锁定记录
        if (RedisUtils.hasKey(loginName)) {
            // 如果存在，删除该锁定记录，实现账户解锁
            RedisUtils.deleteObject(loginName);
        }
        // 返回操作成功的结果
        return R.ok();
    }

}
